package com.meme.editor.level;

import com.meme.editor.EntityObject;
import com.meme.editor.EntityRefLink;
import com.meme.editor.PropertyValueModification;
import com.meme.editor.PropertyValueModificationList;
import com.meme.editor.level.define.ActorTemplate;
import com.meme.editor.level.define.AppearanceDefine;
import com.meme.editor.level.define.PropertyDefineBlock;
import com.meme.editor.level.define.PropertyDefine;
import com.meme.editor.level.define.DefineFile;
import com.meme.editor.level.define.Parameter;
import com.meme.editor.model.sprite2d.ModuleImage;

import com.meme.editor.property.Property;
import com.meme.editor.property.PropertyFactory;
import com.meme.editor.property.control.FileChooserPropertyControl;
import com.meme.io.editor.LevelXmlFileLoader;
import com.meme.io.editor.FileCache;
import com.meme.util.FileUtil;

import java.util.List;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Vector;

import org.apache.log4j.Logger;



public class LevelFile extends EntityObject
{
	static Logger logger = Logger.getLogger(LevelFile.class);
	
	
	public static final String EntityName_ActorSet = "Actors";

	public class ActorSet extends EntityObject
	{
		protected ActorSet () 
		{
			super (EntityName_ActorSet); 
			getPublicProperty (EntityObject.GroupName_Entity, EntityObject.PropertyName_Name).setEditable(false);
		}		
		
		@Override protected boolean isValidChild (EntityObject entity) 
		{ 
			return entity instanceof Actor; 
		}
	}
	
	ActorSet mActorSet = new ActorSet ();
	
	public ActorSet getActorSet ()
	{
		return mActorSet;
	}
	
	// several shortcuts
	
	public void addActor (Actor actor)
	{
		mActorSet.addChild (actor);
	}
	
	public void removeActor (Actor actor)
	{
		mActorSet.removeChild (actor);
	}
	
	public List<EntityObject> getActorList ()
	{
		return mActorSet.getChildren();
	}
	
	public int getActorsCount ()
	{
		return mActorSet.getChildrenCount();
	}
	
//=============================================================================	
	
	
	public final static String GroupName_LevelGroup = "Level Properties";
	public final static String PropertyName_DefineFile        = "Define File";
	public final static String PropertyName_PlayfieldWidth        = "Playfield Width";
	public final static String PropertyName_PlayfieldHeight       = "Playfield Height";
	
	// define file
	
	DefineFile mDefineFile;
	//EntityRefLink mDefineFileRef;


	// entity groups
	LinkedList<ActorGroup> mActorGroups;
	
	// 
	// Vector<MovieAnimation> mMovieAnimations;
	
	int mPlayfieldWidth;
	int mPlayfieldHeight;
	
	public LevelFile ()
	{
		super ("unnamed");
		
		getPublicProperty (EntityObject.GroupName_Entity, EntityObject.PropertyName_Name).setEditable(false);

		createPropertyGroup (GroupName_LevelGroup);
		Property property = createPublicProperty (GroupName_LevelGroup, PropertyName_DefineFile, PropertyFactory.ValueType_String );
		property.setControlType (PropertyFactory.ControlType_ChooseFile);
		property.setParameter(FileChooserPropertyControl.Param_FileFilterParams, "Define Files;xDefine");
	
		createPublicProperty (GroupName_LevelGroup, PropertyName_PlayfieldWidth, PropertyFactory.ValueType_Number);
		createPublicProperty (GroupName_LevelGroup, PropertyName_PlayfieldHeight, PropertyFactory.ValueType_Number);
		
		setPlayfieldWidth (200);
		setPlayfieldHeight (200);
		
		//
		addChild (mActorSet);
	}
	
	
	public void setDefineFile (DefineFile defineFile)
	{
		if (mActorSet.getChildrenCount() == 0)
		{
			mDefineFile = defineFile;
			changePublicPropertyValue(GroupName_LevelGroup, PropertyName_DefineFile, mDefineFile.getHostFilename());
		}
		else
			logger.warn("Can't set define file for a non-enpty level file.");
	}
	
	public DefineFile getDefineFile ()
	{
		return mDefineFile;
	}
	
	public int getPlayfieldWidth ()
	{
		return mPlayfieldWidth;
	}
	
	public int getPlayfieldHeight ()
	{
		return mPlayfieldHeight;
	}
	
	public void setPlayfieldWidth (int width)
	{
		mPlayfieldWidth = width;
		changePublicPropertyValue (GroupName_LevelGroup, PropertyName_PlayfieldWidth, width);
	}
	
	public void setPlayfieldHeight (int height)
	{
		mPlayfieldHeight = height;
		changePublicPropertyValue (GroupName_LevelGroup, PropertyName_PlayfieldHeight, height);
	}
	
	@Override
	protected void _handleModifyingPropertyValues (PropertyValueModificationList modications)
	{			
		super._handleModifyingPropertyValues (modications);
		
		ListIterator<PropertyValueModification> iter = modications.listIterator();
		while ( iter.hasNext() )
		{
			PropertyValueModification mod = iter.next();
			
			if ( mod.mGroupName.equals (GroupName_LevelGroup) )
			{
				if ( mod.mPropertyName.equals (PropertyName_DefineFile) )
				{
					String filename = (String) mod.mNewValue;
					DefineFile defineFile = FileCache.getDefineFile(filename);
					if (defineFile != null)
						setDefineFile (defineFile);
					iter.remove();
				}
				else if ( mod.mPropertyName.equals (PropertyName_PlayfieldWidth) )
				{
					setPlayfieldWidth (( (Float) (mod.mNewValue) ).intValue());
					iter.remove();
				}
				else if ( mod.mPropertyName.equals (PropertyName_PlayfieldHeight) )
				{
					setPlayfieldHeight (( (Float) (mod.mNewValue) ).intValue());
					iter.remove();
				}
			}
		}
	}		
	
	
	
	public static String getFileExtension ()
	{
		return "xLevel";
	}

	@Override
	public boolean isHostObject ()
	{
		return true;
	}
	
	@Override
	public void setHostFilename (String filename)
	{
		super.setHostFilename (filename);
		
		setName (FileUtil.getFilenameWithoutExt(filename));
	}

	@Override
	public String getDefaultName ()
	{
		return "Level";
	}
	
	@Override
	public boolean isValidChild (EntityObject object)
	{
		return object instanceof ActorSet;
	}
	
	@Override
	public Object getProperty (String propertyName)
	{
		if (propertyName.equals("DefineFile"))
		{
			return mDefineFile;
		}
		
		return super.getProperty (propertyName);
	}
	
	

	
	public Actor createActorFromTemplate (ActorTemplate actorTemplate)
	{
		Actor actor = ActorFactory.createActor (actorTemplate.getActorType());
		actor.setName (actorTemplate.getName());
		actor.setZOrder (actorTemplate.getDefaultZOrder());
		actor.setActorTemplate (actorTemplate);
		//addChild (actor);
		addActor (actor);
		
		for (AppearanceDefine appearanceDefine : actorTemplate.getAppearanceDefines() )
		{
			appearanceDefine.makeInstanceForActor (actor);
		}
		
		for (PropertyDefineBlock propertyDefineBlock : actorTemplate.getInstancePropertyDefines())
		{
			propertyDefineBlock.makePropertyGroupForEntity (actor);
		}
		
		return actor;
	}
	
	public Actor cloneActorFromActor (Actor actor)
	{
		if (actor.getParent() != mActorSet)
		{
			return null;
		}
		
		Actor newActor = createActorFromTemplate (actor.getActorTemplate());
		
		EntityObject.sDisableValueValidating = true;
		
		newActor.cloneFrom (actor);
		
		EntityObject.sDisableValueValidating = false;
		
		return newActor;
	}
	
}
